/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_orm.htm
 *
 * Zhiqim Orm is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.orm.executor;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.zhiqim.kernel.model.maps.MapSO;
import org.zhiqim.kernel.model.maps.MapSS;
import org.zhiqim.kernel.util.Closes;
import org.zhiqim.kernel.util.Sqls;
import org.zhiqim.orm.ORMException;
import org.zhiqim.orm.ORMServer;
import org.zhiqim.orm.datasource.ZStatement;
import org.zhiqim.orm.exception.TableNotExistException;

/**
 * 批量处理模式，参数为MapSO的列表
 * 
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class BatchExecutorMap implements BatchExecutor
{
    /**
     * 执行executeBatch处理，全部为通配符匹配
     * 
     * @param server        ORM服务
     * @param conn          数据库连接
     * @param sql           ZSQL语句
     * @param paramList     参数列表
     * @param replaceMap    可替换表
     * @return              返回int，处理条数
     * @throws ORMException 映射异常
     */
    public int[] execute(ORMServer server, Connection conn, String sql, List<?> paramList, MapSS replaceMap) throws ORMException
    {
        PreparedStatement pstmt = null;
        List<String> strList = null;

        try
        {
            // 1.替换可替换符$$
            sql = Sqls.formatReplaceMap(sql, replaceMap);

            // //2.获取通配符##
            List<String> paramKeyList = new ArrayList<>();
            for (int i = 0, start = 0, end = sql.indexOf('#'); end != -1; i++, start = end, end = sql.indexOf('#', start + 1))
            {
                if (i % 2 == 0)
                    continue;
                
                String paramKey = sql.substring(start + 1, end);
                paramKeyList.add(paramKey);
            }

            for (int i=0;i<paramKeyList.size();i++)
            {
                String paramKey = paramKeyList.get(i);
                sql = sql.replaceAll("#" + paramKey + "#", "?");// 把#paramKey#换成?
            }

            // 3.SQL语句处理完毕，保留打印SQL列表
            if (server.isUpdateSqlLog())
            {
                strList = new ArrayList<String>(paramList.size());
                for (int i = 0; i < paramList.size(); i++)
                {
                    String str = sql;
                    strList.add(str);
                }
            }

            // 4.设置传递参数
            boolean isMapSO = (paramList.get(0) instanceof MapSO);

            pstmt = conn.prepareStatement(sql);
            for (int b = 0; b < paramList.size(); b++)
            {// 批插
                String str = null;
                if (server.isUpdateSqlLog())
                    str = strList.get(b);

                Object v = paramList.get(b);
                Map<?, ?> paramMap = isMapSO ? ((MapSO) v).instance() : (Map<?, ?>) v;

                for (int i = 0; i < paramKeyList.size(); i++)
                {
                    String paramKey = paramKeyList.get(i);
                    Object value = paramMap.get(paramKey);

                    if (server.isUpdateSqlLog())
                        str = ZStatement.setParameter(server, pstmt, i + 1, value, str);
                    else
                        ZStatement.setParameter(server, pstmt, i + 1, value);
                }

                // 逐个添加到批量表中
                pstmt.addBatch();

                // 更新完整SQL语句到列表中
                if (server.isUpdateSqlLog())
                {
                    strList.remove(b);
                    strList.add(b, str);
                }
            }

            // 4.批量处理
            int[] rets = pstmt.executeBatch();

            // 5.打印日志
            if (server.isUpdateSqlLog())
            {
                for (String str : strList)
                {
                    str = str.replaceAll("-%6-%-3%-", "?");
                    uSqlLog.info(str);
                }
            }

            return rets;
        }
        catch (SQLException e) 
        {
            if (server.getPolicy().isTableNotExist(e))
                throw new TableNotExistException("[%s][%s]", e, e.getMessage(), sql);
            else
                throw new ORMException("[%s][%s]", e, e.getMessage(), sql);
        }
        catch (Throwable e)
        {
            throw new ORMException("[%s][%s]", e, e.getMessage(), sql);
        }
        finally
        {
            Closes.closeIgnoreException(pstmt);
        }
    }

}
